/**
 * Copyright (c) 2010 deniskir@gmail.com. All rights reserved.
 *
 * @author Denis Kiriusin
 */

package com.dksoftware.combo;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collection;
import java.util.zip.GZIPOutputStream;

import org.apache.commons.io.IOUtils;

class CIOUtils {

	private CIOUtils() {
		// empty constructor
	}

	/**
	 * The method iterates through the collection of files and returns the last
	 * modified date and time as <tt>long</tt> value.
	 * 
	 * @param files
	 *            - collection of files
	 * @return last modified date and time as <tt>long</tt> value, or 0 if files
	 *         collection empty
	 */
	static long lastModified(Collection<File> files) {
		long lastModified = 0;

		for (File file : files) {
			lastModified = Math.max(lastModified, file.lastModified());
		}

		return lastModified;
	}

	/**
	 * The method receives an array of bytes and returns new array of bytes
	 * compressed using <tt>gzip</tt> compression method.
	 * 
	 * @param bytes
	 *            - an array of bytes to compress
	 * @return compressed bytes array
	 * @throws IOException
	 */
	static byte[] gzipContent(final byte[] bytes) throws IOException {
		ByteArrayOutputStream baos = null;
		GZIPOutputStream gzos = null;

		byte[] gzippedBytes = null;

		try {
			baos = new ByteArrayOutputStream();
			gzos = new GZIPOutputStream(baos);

			gzos.write(bytes);
			gzos.finish();
			gzos.flush();
			gzos.close();

			gzippedBytes = baos.toByteArray();
			baos.close();
		} finally {
			if (gzos != null) {
				gzos.close();
			}
			if (baos != null) {
				baos.close();
			}
		}
		return gzippedBytes;
	}

	/**
	 * Copy bytes from an InputStream to an OutputStream. This method buffers
	 * the input internally, so there is no need to use a BufferedInputStream.
	 * The method optionally can add a line break.
	 * 
	 * @param input
	 *            - InputStream to read
	 * @param output
	 *            - OutputStream
	 * @param addLineBreak
	 *            - add line break if <tt>true</tt>
	 * @throws IOException
	 */
	static void readInputStream(final InputStream input,
			final OutputStream output, boolean addLineBreak) throws IOException {
		if (input != null) {
			int length = IOUtils.copy(input, output);

			// add line break between files. We don't have to worry about binary
			// files with this as
			// we'll never be merging multiple binary files together in a single
			// request - just text
			// files such as css or javascript files.
			// This fixes an issue where comments could become unbalanced across
			// multiple files if they are merged together
			if (addLineBreak && (length > 0)) {
				output.write('\n');
			}
		}
	}

	/**
	 * The method receives a collection of files and returns byte array of this
	 * collection.
	 * 
	 * @param files
	 *            - collection of files
	 * @return byte array of files collection
	 * @throws IOException
	 */
	static byte[] getFilesBytes(Collection<File> files) throws IOException {
		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
		for (File file : files) {
			final InputStream inputStream = new FileInputStream(file);
			try {
				readInputStream(inputStream, baos, (files.size() > 1));
			} finally {
				if (inputStream != null) {
					inputStream.close();
				}
			}
		}
		return baos.toByteArray();
	}

}
